import 'package:flutter/material.dart';
import 'package:flutter_baselib/flutter_baselib.dart';
import 'package:flutter_baselib/src/base/view_model/base_common_view_model.dart';
import 'package:flutter_baselib/src/const/constants.dart';

///@date:  2021/3/1 11:09
///@author:  lixu
///@description: ViewModel基类
///进入View页面时，需要http获取数据后才能显示UI的场景继承[BaseViewModel]类，配合[BaseView]使用
///泛型T：进入页面时，http获取数据对象的类型
///1.列表加载(分页加载)
///2.单个对象加载
///封装：通用加载页,集成了加载失败和加载为空的逻辑
abstract class BaseViewModel<T> extends BaseCommonViewModel {
  ///进入页面时（首次）调用接口是否成功
  bool _isLoadingSuccess = false;

  ///加载更多（分页加载）调用接口是否成功
  bool _isLoadingMoreSuccess = false;

  ///当前请求是否是下拉刷新
  bool _isLoadingForPullRefresh = false;

  ///当前请求是否是加载更多
  bool _isLoadingForLoadMore = false;

  ///数据源:针对列表请求
  List<T>? dataList;

  ///数据源:针对单个对象请求
  T? dataBean;

  ///分页加载初始index
  late int _initPageIndex;

  ///分页页数
  late int _pageNum;

  ///分页加载：能否加载更多
  bool _canLoadMore = false;

  ///是否有分页加载功能
  ///默认true
  late bool _isPageLoad;

  ///接口获取的是否是列表数据,否则就是单个数据对象
  ///默认true
  late bool _isRequestListData;

  ///下拉刷新完成提示
  String? _refreshedText = '刷新完成';

  ///每页请求数据个数,用于分页加载
  late int _pageSize;

  BaseViewModel({bool? isRequestListData, bool? isPageLoad, int? initPageIndex, int? pageSize}) : super() {
    _isRequestListData = isRequestListData ?? configIsRequestListData();
    _isPageLoad = isPageLoad ?? configIsPageLoad();
    _initPageIndex = initPageIndex ?? configInitPageIndex();
    _pageNum = _initPageIndex;
    _pageSize = pageSize ?? configPageSize();
    LogUtils.i(tag, '构造:${toString()}');
  }

  int get pageNum => _pageNum;

  int get pageSize => _pageSize;

  String? get refreshedText => _refreshedText;

  bool get canLoadMore => _canLoadMore;

  ///************************根据需求，可选择重写下面方法***************************
  ///进入页面时onLoading方法请求数据类型是否是List数据结构
  ///否则就是单个对象，优先取构造函数传递的参数
  ///子类根据需要可以选择在构造传入或重写该方法
  ///默认是List数据结构
  bool configIsRequestListData() {
    return true;
  }

  ///进入页面时onLoading方法请求的List数据是否是分页加载
  ///子类根据需要可以选择在构造传入或重写该方法
  ///_isRequestListData=true时，该方法才有效
  ///默认是分页加载
  bool configIsPageLoad() {
    return true;
  }

  ///进入页面时onLoading方法请求的List数据分页加载时，起始页Index
  ///子类根据需要可以选择在构造传入或重写该方法
  ///_isRequestListData=true并且_isPageLoad=true 时，该方法才有效
  int configInitPageIndex() {
    return Constants.initPageIndex;
  }

  ///进入页面时onLoading方法请求的List数据分页加载时，页大小
  ///子类根据需要可以选择在构造传入或重写该方法
  ///_isRequestListData=true并且_isPageLoad=true 时，该方法才有效
  int configPageSize() {
    return Constants.pageSize;
  }

  ///配置当前请求Options
  ///子类根据需要可以重写该方法
  Options? configHttpOptions() {
    return null;
  }

  ///配置下拉刷新失败时，是否显示失败的占位View
  ///场景：数据请求成功过，但是在下拉刷新时失败了，此时是否显示失败页
  ///true：显示失败页面
  ///false: 不显示失败页面，继续显示之前请求成功过的数据页面
  ///子类根据需要可以重写该方法
  bool configIsPullRefreshFailShowFailView() {
    return false;
  }

  ///配置加载更多（分页加载）失败时，是否显示失败的占位View
  ///场景：数据请求成功过，但是在加载更多时失败了，此时是否显示失败页
  ///true：显示失败页面
  ///false: 不显示失败页面，继续显示之前请求成功过的数据页面
  ///子类根据需要可以重写该方法
  bool configIsLoadMoreFailShowFailView() {
    return false;
  }

  ///请求失败是否显示Toast提示错误信息
  ///子类根据需求重写
  ///[isLoadMore] 是否是加载更多时，回调的该方法
  bool configIsShowFailToast(bool isLoadMore) {
    return true;
  }

  ///分页加载完所有数据时回调
  ///子类根据需求重写
  void onLoadCompleteAllCallback() {
    ToastUtils.show('已加载完全部');
  }

  ///请求失败回调,子类根据需求重写
  ///[errorBean] http失败响应对象
  ///[isLoadMoreFailCallback] 是否是加载更多失败时回调
  void onHttpErrorCallback(HttpErrorBean errorBean, {bool isLoadMoreFailCallback = false}) {}

  ///************************根据需求，可选择重写上面方法***************************

  ///************************下面是必须重写的方法***************************
  ///获取http请求参数
  Map<String, dynamic> getRequestParams();

  ///获取http请求url
  String getUrl();

  ///设置能否加载更多
  void setCanLoadMore(bool value) {
    _canLoadMore = value;
  }

  ///************************上面是必须重写的方法***************************

  ///加载数据
  ///第一次请求或下拉刷新时调用(请求参数设置为初始值)
  @override
  Future onLoading(BuildContext context) async {
    LogUtils.i(getTag(), 'onLoading');

    if (isLoading) {
      LogUtils.w(getTag(), 'onLoading() is Loading');
      return;
    }

    isLoading = true;
    _refreshedText = '刷新成功';

    CancelToken cancelToken = CancelToken();
    cancelTokenList.add(cancelToken);

    ///保存当前分页加载pageNum，当下拉刷新失败时，恢复之前的pageNum
    int oldPageNum = _pageNum;

    ///请求失败回调
    var onError = (HttpErrorBean errorBean) {
      if (_isRequestListData) {
        ///当下拉刷新失败时，恢复之前的pageNum
        _pageNum = oldPageNum;
      }

      ///下拉刷新请求失败，并且设置显示FailView，此时清除之前获取的数据
      if (_isLoadingForPullRefresh && configIsPullRefreshFailShowFailView()) {
        dataBean = null;
        dataList = null;
      }

      _isLoadingSuccess = false;
      _refreshedText = '刷新失败';
      onHttpErrorCallback(errorBean);
    };

    ///请求完成回调
    var onComplete = () {
      isLoading = false;
      cancelTokenList.remove(cancelToken);
    };

    if (_isRequestListData) {
      ///下拉刷新或第一次加载时
      _pageNum = _initPageIndex;

      ///请求列表数据
      await api.requestList<T>(
        getUrl(),
        params: getRequestParams(),
        option: configHttpOptions(),
        isShowLoading: false,
        isShowFailToast: configIsShowFailToast(false),
        cancelToken: cancelToken,
        onError: onError,
        onComplete: onComplete,
        onSuccess: (List<T>? list) {
          ///请求成功回调
          _isLoadingSuccess = true;
          dataList = [];
          list = list ?? [];

          ///解析json
          dataList!.addAll(list);

          if (_isPageLoad) {
            ///list分页加载
            if (list.length < _pageSize) {
              _canLoadMore = false;
            } else {
              _canLoadMore = true;
              _pageNum++;
            }
          } else {
            ///list没有分页加载
            _canLoadMore = false;
          }
        },
      );
    } else {
      ///请求单个数据对象
      await api.request<T>(
        getUrl(),
        params: getRequestParams(),
        option: configHttpOptions(),
        isShowLoading: false,
        isShowFailToast: configIsShowFailToast(false),
        cancelToken: cancelToken,
        onError: onError,
        onComplete: onComplete,
        onSuccess: (T? bean) {
          ///请求成功回调
          _isLoadingSuccess = true;
          dataBean = bean;
        },
      );
    }
  }

  ///加载更多:针对分页加载
  Future onLoadingMore(context) async {
    LogUtils.i(getTag(), 'onLoadMore:$_canLoadMore');
    if (_canLoadMore) {
      if (isLoading) {
        LogUtils.w(getTag(), 'onLoadMore is Loading');
        return;
      }

      _isLoadingForLoadMore = true;
      isLoading = true;

      CancelToken cancelToken = CancelToken();
      cancelTokenList.add(cancelToken);

      await api.requestList<T>(
        getUrl(),
        params: getRequestParams(),
        option: configHttpOptions(),
        isShowLoading: false,
        isShowFailToast: configIsShowFailToast(true),
        onSuccess: (List<T>? list) {
          ///请求成功回调
          _isLoadingMoreSuccess = true;

          if (list != null) {
            dataList ??= [];
            dataList?.addAll(list);

            if (list.length < _pageSize) {
              _canLoadMore = false;
            } else {
              _canLoadMore = true;
              _pageNum++;
            }
          }
        },
        onError: (HttpErrorBean errorBean) {
          _isLoadingMoreSuccess = false;

          ///列表加载更多请求失败，并且设置显示FailView，此时清除之前获取的数据
          if (configIsLoadMoreFailShowFailView()) {
            dataList = null;
          }

          ///请求失败回调
          onHttpErrorCallback(errorBean, isLoadMoreFailCallback: true);
        },
        onComplete: () {
          ///请求完成回调
          isLoading = false;
          cancelTokenList.remove(cancelToken);
        },
      );
      notifyListeners();
    } else {
      onLoadCompleteAllCallback();
    }
  }

  ///手动下拉刷新
  Future onPullToRefresh(BuildContext context) async {
    _isLoadingForPullRefresh = true;
    await onLoading(context);
    notifyListeners();
  }

  ///请求是否成功
  @override
  bool isSuccess() {
    LogUtils.e(getTag(), "isSuccess");
    if (_isLoadingSuccess ||
        _isLoadingMoreSuccess ||
        (_isLoadingForPullRefresh && !configIsPullRefreshFailShowFailView()) ||
        (_isLoadingForLoadMore && !configIsLoadMoreFailShowFailView())) {
      _isLoadingForPullRefresh = false;
      _isLoadingForLoadMore = false;

      if (_isRequestListData) {
        return dataList != null && dataList!.length > 0;
      } else {
        return dataBean != null;
      }
    } else {
      _isLoadingForPullRefresh = false;
      _isLoadingForLoadMore = false;

      return false;
    }
  }

  ///请求是否失败
  @override
  bool isFail() {
    return !_isLoadingSuccess && !_isLoadingMoreSuccess;
  }

  ///请求数据是否为空
  @override
  bool isEmpty() {
    if (_isRequestListData) {
      return dataList == null || dataList!.isEmpty;
    } else {
      return dataBean == null;
    }
  }
}
